redis.replicate_commands()

-- tokens_key = request_rate_limiter.{id}.tokens
-- timestamp_key = request_rate_limiter.{id}.timestamp
-- e.g request_rate_limiter.{api001}.tokens, request_rate_limiter.{api001}.timestamp
-- @see ApiRedisRateLimiter.getKeys
local tokens_key = KEYS[1]
local timestamp_key = KEYS[2]
--redis.log(redis.LOG_WARNING, "tokens_key " .. tokens_key)

-- replenishRate, burstCapacity, "", requestedTokens
-- @see ApiRedisRateLimiter.isAllowed # scriptArgs
local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2])
-- 当前时间戳，精确到微秒
local now = redis.call('TIME')[1]
local requested = tonumber(ARGV[4])
-- fill_time: 空桶加满令牌需要的时间
local fill_time = capacity/rate
-- 过期时间,  rate = 5, capacity = 5, fill_time = 1, ttl = 2
--0----1----2----3----4-> time
local ttl = math.floor(fill_time*2)

--redis.log(redis.LOG_WARNING, "rate " .. ARGV[1])
--redis.log(redis.LOG_WARNING, "capacity " .. ARGV[2])
--redis.log(redis.LOG_WARNING, "now " .. now)
--redis.log(redis.LOG_WARNING, "requested " .. ARGV[4])
--redis.log(redis.LOG_WARNING, "filltime " .. fill_time)
--redis.log(redis.LOG_WARNING, "ttl " .. ttl)

-- 查询上一次的token值, e.g request_rate_limiter.{api001}.tokens = 3
local last_tokens = tonumber(redis.call("get", tokens_key))
if last_tokens == nil then
  last_tokens = capacity
end
--redis.log(redis.LOG_WARNING, "last_tokens " .. last_tokens)
-- 查询上一次记录的时间戳, e.g request_rate_limiter.{api001}.timestamp = 1111111111
local last_refreshed = tonumber(redis.call("get", timestamp_key))
if last_refreshed == nil then
  last_refreshed = 0
end
--redis.log(redis.LOG_WARNING, "last_refreshed " .. last_refreshed)
-- delta: 过了多少时间了
local delta = math.max(0, now-last_refreshed)
-- 重新计算当前桶中应该有多少令牌
local filled_tokens = math.min(capacity, last_tokens+(delta*rate))
-- 计算桶中令牌数是否够本次请求所需的令牌数，一般一次请求需要一个令牌 requested == 1
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
local allowed_num = 0
if allowed then
-- 如果允许本次令牌的申请, 则剩余令牌数需要减去本次申请的令牌数, 并且设置allowed_num = 1
  new_tokens = filled_tokens - requested
  allowed_num = 1
end

--redis.log(redis.LOG_WARNING, "delta " .. delta)
--redis.log(redis.LOG_WARNING, "filled_tokens " .. filled_tokens)
--redis.log(redis.LOG_WARNING, "allowed_num " .. allowed_num)
--redis.log(redis.LOG_WARNING, "new_tokens " .. new_tokens)

if ttl > 0 then
  redis.call("setex", tokens_key, ttl, new_tokens)
  redis.call("setex", timestamp_key, ttl, now)
end

-- return { allowed_num, new_tokens, capacity, filled_tokens, requested, new_tokens }
return { allowed_num, new_tokens }
